/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2021-07-07     acer       the first version
 */
#include "rs485.h"
#include "setting.h"
#include <sys/socket.h> /* 使用BSD socket，需要包含socket.h头文件 */
#include <rtdevice.h>
#include <board.h>

#define SERIAL_UART_NAME       "uart3"  /* 串口设备名称 */

#define RS485_RE GET_PIN(C, 0)

extern device_param_t device_setting;

/* 串口接收消息结构*/
struct rx_msg
{
    rt_device_t dev;
    rt_size_t size;
};
/* 串口设备句柄 */
static rt_device_t serial = RT_NULL;
/* 消息队列控制块 */
static struct rt_messagequeue rx_mq;
//发送方法
static func_ptr_arg2_ret_t to_send;

/* 接收数据回调函数 */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
    struct rx_msg msg;
    rt_err_t result;
    msg.dev = dev;
    msg.size = size;

    result = rt_mq_send(&rx_mq, &msg, sizeof(msg));
    if ( result == -RT_EFULL)
    {
        /* 消息队列满 */
        rt_kprintf("message queue full！\n");
    }
    return result;
}

static void serial_thread_entry(void *parameter)
{
    struct rx_msg msg;
    rt_err_t result;
    rt_uint32_t rx_length;
    static char rx_buffer[RT_SERIAL_RB_BUFSZ + 1];

    while (1)
    {
        rt_memset(&msg, 0, sizeof(msg));
        /* 从消息队列中读取消息*/
        result = rt_mq_recv(&rx_mq, &msg, sizeof(msg), RT_WAITING_FOREVER);
        if (result == RT_EOK)
        {
            /* 从串口读取数据*/
            rx_length = rt_device_read(msg.dev, 0, rx_buffer, msg.size);
            //发送到
            to_send((rt_uint8_t *)rx_buffer, rx_length);
        }
    }
}

int rs485_init(func_ptr_arg2_ret_t send)
{
    rt_err_t ret = RT_EOK;
    char uart_name[RT_NAME_MAX];
    static char msg_pool[256];
    struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;  /* 初始化配置参数 */

    //设置发送方法
    to_send = send;

    rt_strncpy(uart_name, SERIAL_UART_NAME, RT_NAME_MAX);

    /* 收发引脚为输出模式 */
    rt_pin_mode(RS485_RE, PIN_MODE_OUTPUT);
    /* 默认低电平 */
    rt_pin_write(RS485_RE, PIN_LOW);

    /* 查找串口设备 */
    serial = rt_device_find(uart_name);
    if (!serial)
    {
        rt_kprintf("find %s failed!\n", uart_name);
        return RT_ERROR;
    }

    /* step2：修改串口配置参数 */
    config.baud_rate = device_setting->rs485_params.baud;           //修改波特率为 9600
    config.data_bits = device_setting->rs485_params.data_bit;       //数据位 8
    config.stop_bits = device_setting->rs485_params.stop_bit;       //停止位 1
    config.bufsz     = 128;                                         //修改缓冲区 buff size 为 128
    config.parity    = device_setting->rs485_params.parity;         //无奇偶校验位

    /* step3：控制串口设备。通过控制接口传入命令控制字，与控制参数 */
    rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &config);

    /* 初始化消息队列 */
    rt_mq_init(&rx_mq, "r4rx_mq",
               msg_pool,                 /* 存放消息的缓冲区 */
               sizeof(struct rx_msg),    /* 一条消息的最大长度 */
               sizeof(msg_pool),         /* 存放消息的缓冲区大小 */
               RT_IPC_FLAG_FIFO);        /* 如果有多个线程等待，按照先来先得到的方法分配消息 */

    /* 以 DMA 接收及轮询发送方式打开串口设备 */
    rt_device_open(serial, RT_DEVICE_FLAG_DMA_RX);
    /* 设置接收回调函数 */
    rt_device_set_rx_indicate(serial, uart_input);

    /* 创建 serial 线程 */
    rt_thread_t thread = rt_thread_create("rs485", serial_thread_entry, RT_NULL, 1024, 25, 10);
    /* 创建成功则启动线程 */
    if (thread != RT_NULL)
    {
        rt_thread_startup(thread);
    }
    else
    {
        ret = RT_ERROR;
    }

    return ret;
}

rt_uint8_t rs485_send(rt_uint8_t *data, rt_uint32_t length)
{
    rt_uint8_t err = 1;
    if(serial != RT_NULL)
    {
        rt_pin_write(RS485_RE, PIN_HIGH);
        if(rt_device_write(serial, 0, data, length) < 0)
        {
            err = 0;
        }
        rt_pin_write(RS485_RE, PIN_LOW);
    }
    else
    {
        err = 0;
    }
    return err;
}
